/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package utils;//将各种格式的用户输入转换为神经网络可以处理的标准化格式

/**
 *
 * @author Raise
 */
import java.awt.*;
import java.awt.image.BufferedImage;

//将用户提供的各种格式的图片转换成为统一格式3
//通过双线性插值保持图像信息，提高识别准确率
//预处理步骤分离，针对不同需求使用特定的方法
//处理后的图像可以在训练、测试、验证中使用

public class ImageProcessor {
    //提供完整的图像预处理流水线，只需调用一个方法便可以完成所有的预处理步骤
    //对图像进行预处理，返回统一的像素数组（28*28=784维）
    public double[] preprocessImage(BufferedImage image) {
        if (image == null) {
            throw new IllegalArgumentException("输入图像不能为null");
        }
        
        // 按顺序执行三个预处理步骤，调整大小为28x28，确保输入图像符合MNIST数据集规范，提高识别准确率
        BufferedImage resized = resizeImage(image, 28, 28);
        // 转换为灰度图
        BufferedImage gray = toGrayScale(resized);
        // 获取像素数组并归一化
        return getPixelArray(gray);
    }

    //调整图像大小
    public BufferedImage resizeImage(BufferedImage original, int width, int height) {
        //创建指定尺寸的新图像并进行缩放绘制，确保所有的输入图像尺寸统一，符合神经网络的输入要求
        BufferedImage resized = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = resized.createGraphics();
        //设置渲染提示为双线性插值，缩放时图像质量更好，减少锯齿现象
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(original, 0, 0, width, height, null);
        g.dispose();//及时释放图形资源
        return resized;
    }
    
    //将图像转换为灰度图
    public BufferedImage toGrayScale(BufferedImage image) {
        //检查是否已经是灰度图，直接返回，避免不必要的转换浪费时间，提高处理效率并减少资源消耗
        if (image.getType() == BufferedImage.TYPE_BYTE_GRAY) {
            return image;
        }

        //创建新的灰度图，减少数据维度，简化神经网络，提高计算效率
        BufferedImage gray = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g = gray.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return gray;
    }
    //从灰度图像中获取像素数组，并进行归一化和颜色反转（符合MNIST格式）
    private double[] getPixelArray(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();
        double[] pixels = new double[width * height];
        
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb = image.getRGB(x, y);
                //获取红色通道（因为灰度图中R=G=B，所以取拿个通道都一样）
                int gray = (rgb >> 16) & 0xFF; // 取红色通道作为灰度值
                // 反转颜色并进行归一化（归一化到0-1之间）：黑色背景变为白色，白色笔画变为黑色（符合MNIST格式，且归一化后数值范围适合神经网络处理）
                //注意：MNIST数据集是白底黑字，而用户提供的可能失白底黑字，所以要用255来减
                pixels[y * width + x] = (255 - gray) / 255.0;
            }
        }
        return pixels;
    }
    
    //为了显示目的调整图像的大小（保持宽高比），使其能够在UI中展示图片时保持良好的视觉效果，不变形
    public BufferedImage resizeForDisplay(BufferedImage original, int maxWidth, int maxHeight) {
        //计算等比例缩放尺寸的逻辑
        int originalWidth = original.getWidth();
        int originalHeight = original.getHeight();
        
        // 计算等比例缩放尺寸
        double widthRatio = (double) maxWidth / originalWidth;
        double heightRatio = (double) maxHeight / originalHeight;
        double ratio = Math.min(widthRatio, heightRatio);
        
        int newWidth = (int) (originalWidth * ratio);
        int newHeight = (int) (originalHeight * ratio);
        
        BufferedImage resized = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = resized.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(original, 0, 0, newWidth, newHeight, null);
        g.dispose();
        
        return resized;
    }
}
